using System;
using System.Collections.Generic;

namespace FrameIdentityReq.Frames
{
    public class BitsVariable
    {
        public IList<byte> Buffer { get; }
        public int Index { get; private set; }
        public int Count { get; private set; }
        public int CountInByte { get { return 8 - (Index & 0x7); } }
        public int IndexOfCurrentByte { get { return Index >> 3; } }

        public BitsVariable(IList<byte> buffer, int index)
            : this(buffer, index, buffer.Count << 3 - index) { }

        public BitsVariable(IList<byte> buffer, int index, int count)
        {
            Buffer = buffer;
            Index = index;
            Count = count;
        }

        public void CopyTo(BitsVariable target, int count)
        {
            int minCount = 0;
            Func<int, int, int, int> Min = (a, b, c) => Math.Min(a, Math.Min(b, c));
            Action<BitsVariable> ReduceCount = (o) => o.ReduceCount(minCount);

            for (; count > 0; count -= minCount)
            {
                minCount = Min(count, CountInByte, target.CountInByte);

                byte sourceBits = GetCurrentBits(minCount, target.CountInByte);
                target.SetCurrntBits(sourceBits, minCount, target.CountInByte);

                ReduceCount(this);
                ReduceCount(target);
            }
        }

        /// <summary>
        /// 返回当前字节内的比特串
        /// </summary>
        /// <returns></returns>
        public byte GetCurrntBits()
        {
            // 保留高位比特, 低位清零
            Func<byte, byte> GetHight = (x) =>
            {
                x >>= CountInByte;
                x <<= CountInByte;
                return x;
            };

            byte bits = Buffer[IndexOfCurrentByte];
            bits ^= GetHight(bits); // 高位对高位XOR运算, 高位清零, 低位保留.
            return bits;
        }

        /// <summary>
        /// 返回当前字节内的比特片段
        /// </summary>
        /// <param name="count">有效的比特个数</param>
        /// <returns></returns>
        public byte GetCurrntBits(int count)
        {
            byte bits = GetCurrntBits();
            bits >>= CountInByte - count;
            return bits;
        }

        /// <summary>
        /// 返回当前字节内的比特片段
        /// </summary>
        /// <param name="count">有效的比特个数</param>
        /// <param name="width">比特总宽度.不足的在末尾补零</param>
        /// <returns></returns>
        public byte GetCurrentBits(int count, int width)
        {
            byte bits = GetCurrntBits(count);
            return bits <<= width - count;
        }

        /// <summary>
        /// 保存比特到数组
        /// </summary>
        /// <param name="oldBits">当前数组中保存位置的比特串. 用于清除该位置比特串, 相当于掩码.</param>
        /// <param name="newBits">要保存到数组的比特串.</param>
        public void SetCurrntBits(byte oldBits, byte newBits)
        {
            Buffer[IndexOfCurrentByte] ^= oldBits; // 清除
            Buffer[IndexOfCurrentByte] ^= newBits; // 写入
        }

        /// <summary>
        /// 保存比特到数组
        /// </summary>
        /// <param name="newBits">要保存到数组的比特串</param>
        /// <param name="count">有效比特串的宽度</param>
        /// <param name="width">从0比特位到最高有效比特位的总宽度</param>
        public void SetCurrntBits(byte newBits, int count, int width)
        {
            SetCurrntBits(GetCurrentBits(count, width), newBits);
        }

        /// <summary>
        /// 减少未被处理的比特串长度. 调整内部当前指针.
        /// </summary>
        /// <param name="count">被减少的比特串长度</param>
        public void ReduceCount(int count)
        {
            Index += count;
            Count -= count;
        }
    }
}